/*
 * @Author: bor_fish 1219854025@qq.com
 * @Date: 2025-04-22 17:21:27
 * @LastEditors: bor_fish 1219854025@qq.com
 * @LastEditTime: 2025-05-21 10:57:26
 * @FilePath: /myCAN/Listener.cpp
*/

#include "Listener.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <unistd.h>
#include <iostream>
#include <cstring>

#include <iomanip>
//static 类内定义 类外声明
std::atomic<bool> CanListener::global_running_(true);

/**
 * @description: 用来Debug调试信息
 * @param {can_frame&} frame
 * @param {int} interface_index
 * @param {int} packet_index
 * @return {*}
 */
void CanListener::printBufDebugInfo(const can_frame& frame, int interface_index,int packet_index)
{
	std::cout << "========================" << std::endl;
	std::cout << "ProcessDataLoop Running!" << std::endl;
	// 打印完整的frame.can_id
	uint32_t frameID;
	std::memcpy(&frameID, 
		&packet_Buffer_[interface_index][packet_index][21], 
		sizeof(uint32_t));
		std::cout << "Frame ID: 0x" << std::hex 
		<< std::setfill('0') << std::setw(8) 
		<< frameID << std::endl;


	//打印时间戳
	std::cout << "TimeStamp: ";
	    // 从数组中读取时间戳（从第2个字节开始，读取8字节）
		int64_t stored_timestamp;
		std::memcpy(&stored_timestamp, 
					&packet_Buffer_[interface_index][packet_index][2], 
					sizeof(int64_t));
    // 将纳秒转换为秒和纳秒部分
    auto seconds = stored_timestamp / 1000000000;
    auto nanoseconds = stored_timestamp % 1000000000;
    // 转换为时间结构
    std::time_t time_seconds = seconds;
    std::tm* timeinfo = std::localtime(&time_seconds);
    // 格式化输出
    std::cout << std::put_time(timeinfo, "%Y-%m-%d %H:%M:%S")
              << "."
              << std::setfill('0') << std::setw(3)
              << std::endl;


	/* 打印数据长度 */
	printf("[%d] ", frame.can_dlc);
	/* 打印数据 */
	for (size_t i = 0; i < frame.can_dlc; i++) {
		printf("%02x ", packet_Buffer_[interface_index][packet_index][26 + i]);
		
	}
	printf("\n");
	std::cout << "========================" << std::endl;
}

int sockfd = -1;//套接字文件描述符

/**
 * @description: 初始化CAN套接字
 * @return {*}
 */
void CanListener::Sockets_Init() {
    
    struct ifreq ifr = {0};
    struct sockaddr_can Can_Addr = {0};

    std::cout << "Sockets_Init" << std::endl;

    sockfd = socket(PF_CAN,SOCK_RAW,CAN_RAW);
    if(sockfd < 0)
    {
        perror("socket error");
        exit(EXIT_FAILURE);
    }

    //指定绑定设备
    strcpy(ifr.ifr_name, kInterfaceName[0].c_str());
    ioctl(sockfd,SIOCGIFINDEX,&ifr);
    Can_Addr.can_family = AF_CAN;
    Can_Addr.can_ifindex = ifr.ifr_ifindex;

    //将套接字与CAN进行绑定
    if(bind(sockfd,reinterpret_cast<struct sockaddr*>(&Can_Addr),sizeof(Can_Addr)) < 0)
    {
        perror("bind error");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    can_sockets_.push_back(sockfd);

}
/**
 * @description: 监听CAN通路循环线程
 * @return {*}
 */
void CanListener::Listen_Loop()
{
	struct can_frame frame = {0};

    while(true) {
		//std::cout << "Listen_Loop" << std::endl;
		//多路IO复用文件描述符集-存储一组文件描述符
		fd_set read_fds;
		//初始化，将所有的文件描述符标记为未选中状态
		FD_ZERO(&read_fds);
		//这遍轮训接收到的最大描述符
		int max_fd = -1;

		//将所有CAN套接字添加到监视集合中,找出最大的文件描述符值,多路I/O复用的关键步骤
		for(int sockfd : can_sockets_) {
			FD_SET(sockfd, &read_fds);
			if(sockfd > max_fd) max_fd = sockfd;
		}

		//实现了多路IO复用，允许同时监听多个CAN接口，采用阻塞方式等待数据
		int ret = select(max_fd + 1, &read_fds, nullptr, nullptr, nullptr);
		if(ret < 0)
		{
			perror("Select");
			break;
		}
		
		//当前套接字有数据待处理时，从有数据的CAN接口读取一帧数据，数据存储在frame结构体中
		for(size_t i = 0;i < can_sockets_.size();++i)
		{
			if(FD_ISSET(can_sockets_[i], &read_fds)) {
				read(can_sockets_[i], &frame,sizeof(frame));
				ProcessData(frame,i);
			}
		}
	}
}
/**
 * @description: 处理CAN发送过来的数据
 * @param {can_frame&} frame	传递 CAN 数据帧的详细信息
 * @param {int} interface_index	CAN通道索引-是哪一路有新数据
 * @return {*}
 */
void CanListener::ProcessData(const can_frame& frame, int interface_index)
{
	//给读取记录数据的过程上锁
	{
	std::lock_guard<std::mutex> lock(linstener_mutex_);
	//读取某一路CAN数据包，确保索引在范围内
	int packet_index = write_indices_[interface_index] % kBufferSize;

	if(static_cast<size_t>(write_indices_[interface_index]) < kBufferSize) {
		// 设置帧类型
		packet_Buffer_[interface_index][packet_index][25] =  (frame.can_id & CAN_RTR_FLAG) ? 1 : 0; 
		//清空下标1、2的字节
		std::memset(packet_Buffer_[interface_index][packet_index].data() + 1 , 0, 2);

		auto currentTimeStamp = std::chrono::system_clock::now();
		auto timeStamp = std::chrono::duration_cast<std::chrono::nanoseconds>
		(currentTimeStamp.time_since_epoch()).count();//获取当期时间戳

		//从第3个字节开始存储时间戳
		std::memcpy(&packet_Buffer_[interface_index][packet_index][2], 
			&timeStamp, sizeof(timeStamp));

		// 存储DLC到第11字节
		packet_Buffer_[interface_index][packet_index][25] = frame.can_dlc;

		//从22个字节开始存储ID值
		uint32_t frameID = frame.can_id & CAN_EFF_MASK;
		std::memcpy(&packet_Buffer_[interface_index][packet_index][21],
			&frameID, sizeof(frameID));

		//如果是数据帧为ture
		if(!(frame.can_id & CAN_RTR_FLAG)) {
			// 判断剩下的长度还够不够用
			if(frame.can_dlc <= (kFrameSize - 26)) {
				std::memcpy(&packet_Buffer_[interface_index][packet_index][26],
					frame.data, frame.can_dlc);
				packet_Buffer_[interface_index][packet_index][26 + frame.can_dlc] = '\0';
			}else {
				std::cerr << "错误，存储字节数不够" << interface_index << std::endl;
			}
		}

		
		// 3. 计算CRC并存储到第12、13字节-模拟硬件CRC后期可去掉
		// CRC计算范围：ID(4字节)[21-24] + DLC(1字节)[25] + Data[26~(26+dlc-1)]
		// 这里我们将ID、DLC、Data拼成一段buffer再算CRC
		uint8_t crc_buffer[4 + 1 + 8] = {0}; // 最大8字节数据
		std::memcpy(crc_buffer, &packet_Buffer_[interface_index][packet_index][21], 4); // ID
		crc_buffer[4] = packet_Buffer_[interface_index][packet_index][25]; // DLC
		uint8_t dlc = frame.can_dlc;
		if (dlc > 0) {
			std::memcpy(crc_buffer + 5, &packet_Buffer_[interface_index][packet_index][26], dlc); // Data
		}
		uint16_t crc = calc_can_crc(crc_buffer, 4 + 1 + dlc);
		std::memcpy(&packet_Buffer_[interface_index][packet_index][12], &crc, sizeof(uint16_t));


		//Debug
		//printBufDebugInfo(frame, interface_index, packet_index);

		// 更新写入索引，循环利用
		write_indices_[interface_index] = (write_indices_[interface_index] + 1) % 6000;
		//Debug
		// std::cout << "write_indices_[interface_index] : " <<write_indices_[interface_index] 
		// << std::endl;
	}
		// 广播数据到所有诊断线程
		broadcastData(frame, interface_index);
	}
}
/**
 * @description: 广播数据到所有诊断线程
 * @param {can_frame&} frame	传递 CAN 数据帧的详细信息
 * @param {int} interface_index	CAN通道索引-是哪一路有新数据
 * @return {*}
 */
void CanListener::broadcastData(const can_frame& frame, int interface_index)
{
	// 将数据放入每个诊断线程的队列
	for (int i = 0; i < kDiagnosticThreadCount; ++i) {
		std::lock_guard<std::mutex> lock(broadcast_mutexes_[i]);
		broadcast_queues_[i].push({frame, interface_index});
		broadcast_cvs_[i].notify_one();
	}
}

/**
 * @description: 从指定诊断线程的独立队列获取CAN数据（线程安全）- 由诊断线程调用
 * @param {can_frame&} frame	传递 CAN 数据帧的详细信息
 * @param {int} interface_index	CAN通道索引-是哪一路有新数据
 * @param {int} thread_index	诊断线程索引
 * @return {*}
 */
bool CanListener::getNextData(can_frame& frame, int& interface_index, int thread_index)
{
	// 获取线程专属锁
    std::unique_lock<std::mutex> lock(broadcast_mutexes_[thread_index]);
    // 等待新数据或停止信号
	// 阻塞等待直到队列有数据或停止运行（条件变量避免忙等待）
    broadcast_cvs_[thread_index].wait(lock, [this, thread_index]() { 
        return !broadcast_queues_[thread_index].empty() || !isRunning(); 
    });
	 // 运行状态检查
    if (!isRunning()) {
        return false;
    }

    // 从专属队列提取数据（先进先出）
    auto data = broadcast_queues_[thread_index].front();
    broadcast_queues_[thread_index].pop();
	// 输出CAN帧结构体
    frame = data.first;
	// 输出CAN接口索引
    interface_index = data.second;
    return true;
}
/**
 * @description: 通知数据已处理-由诊断线程调用
 * @return {*}
 */
void CanListener::notifyDataProcessed()
{
    processed_count_++;
}
/**
 * @description: 安全退出线程-主函数调用
 * @return {*}
 */
void CanListener::Stop()
{
    std::cout << "Stopping CAN listener..." << std::endl;
	//使用原子操作设置全局运行标志为false
	global_running_.store(false, std::memory_order_release);
    // 通知所有等待的条件变量
    for (auto& cv : broadcast_cvs_) {
        cv.notify_all();
    }
    // 关闭所有CAN套接字
    for (int fd : can_sockets_) {
        close(fd);
    }
    can_sockets_.clear();
    std::cout << "CAN listener stopped." << std::endl;
}